from typing import Any
import requests
import json
from http.cookiejar import MozillaCookieJar

class TwitterParser:
    TWEET_ENDPOINT = 'https://twitter.com/i/api/graphql/nz90rnWCU72rA6b0KwUIow/TweetDetail'
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0'

    def __init__(
        self, 
        config: str = ".twitter_parser_config.json", 
        cookies: str|dict[str, str] = "twitter_parser_cookies.txt"
    ) -> None:
        with open(config, "rt") as f:
            self._config = json.load(f)
        self._bearer_token = self._config["BEARER_TOKEN"]

        if isinstance(cookies, dict):
            self._cookies = cookies
            self._csrf = cookies['ct0']
        else:
            self._cookies = MozillaCookieJar(cookies)
            self._cookies.load()
        
            self._csrf = None
            for cookie in self._cookies:
                if cookie.name == 'ct0':
                    self._csrf = cookie.value
                    break
                
        self._headers = {
            'authorization': f'Bearer {self._bearer_token}',
            'content-type': 'application/json',
            'dnt': '1',
            'user-agent': self.USER_AGENT,
            'x-csrf-token': self._csrf,
            'x-twitter-active-user': 'yes',
            'x-twitter-auth-type': 'OAuth2Session',
        }
        
    def get_tweet(self, tweet_id):
        variables = {
            "focalTweetId": tweet_id,
            "with_rux_injections": False,
            "includePromotedContent": False,
            "withCommunity": False,
            "withQuickPromoteEligibilityTweetFields": False,
            "withBirdwatchNotes": False,
            "withVoice": True,
            "withV2Timeline": True
        }

        params = {
            'variables': json.dumps(variables),
            'features': '{"rweb_tipjar_consumption_enabled":false,"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"communities_web_enable_tweet_community_results_fetch":true,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":true,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"rweb_video_timestamps_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_enhance_cards_enabled":false}',
            'fieldToggles': '{"withArticleRichContentState":true,"withArticlePlainText":false}',
        }
        
        self._response = requests.get(
            self.TWEET_ENDPOINT,
            params=params,
            cookies=self._cookies,
            headers=self._headers,
        )
        
        self.tweet = self.parse_response()
        self.tweet_content = self.tweet["tweet"]
        self.tweet_user = self.tweet["user"]

        return self.tweet
        
    def parse_response(self) -> dict[str, Any]:
        json = self._response.json()
        
        if "errors" in json:
            if (
                json.get("errors")[0].get("kind") == "NonFatal"
                and "No status found with that ID" in json.get("errors")[0].get("message")
            ):
                return {
                    "tweet": None,
                    "user": None,
                    "error": 404,
                }
            else:
                print(json)
                return {
                    "tweet": None,
                    "user": None,
                    "error": 404,
                }

        tweet_info = (
            json
            .get('data')
            .get('threaded_conversation_with_injections_v2')
            .get('instructions')
        )
    
        for instruction in tweet_info:
            if instruction.get('type') == 'TimelineAddEntries':
                tweet_info = instruction
                break
        
        tweet_info = (
            tweet_info
            .get('entries')
        )
    
        for entry in tweet_info:
            if entry.get('entryId').startswith('tweet-'):
                tweet_info = entry
                break
        
        tweet_info = (
            tweet_info
            .get('content')
            .get('itemContent')
            .get('tweet_results')
            .get('result')
        )
        
        if tweet_info.get('tombstone'):
            return {
                "tweet": {
                    "full_text": tweet_info.get('tombstone').get('text').get('text')
                },
                "user": None,
                "error": 410,
            }
            

        tweet_data = tweet_info.get('legacy')
        user_data = tweet_info.get('core').get('user_results').get('result')
        
        return {
            "tweet": tweet_data,
            "user": user_data,
            "error": None,
        }

    def tweet_text(self) -> str:
        return self.tweet_content.get('full_text', '').rsplit(" https://t.co/", 1)[0]

    def tweet_photos(self) -> list[str]:
        return [
            media.get("media_url_https")
            for media in
            self.tweet_content.get('entities').get('media')
            if media.get("type") == "photo"
        ]

    def tweet_videos(self) -> list[str]:
        return [
            media.get("video_info").get("variants")[-1].get("url")
            for media in
            self.tweet_content.get('entities').get('media')
            if media.get("type") == "video"
        ]

    def tweet_media(self) -> dict[str, str|list[str]]:
        return {
            "text": self.tweet_text(),
            "photos": self.tweet_photos(),
            "videos": self.tweet_videos(),
        }
